package sf.database.jdbc.type;

import sf.tools.IOUtils;

import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;
import java.sql.CallableStatement;
import java.sql.Clob;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;

public class StringClobType implements TypeHandler<String> {
    public String get(ResultSet rs, String colName) throws SQLException {
        Object obj = rs.getObject(colName);
        return changeValue(obj);
    }

    public String get(ResultSet rs, int index) throws SQLException {
        Object obj = rs.getObject(index);
        return changeValue(obj);
    }

    public String get(CallableStatement rs, int index) throws SQLException {
        Object obj = rs.getObject(index);
        return changeValue(obj);
    }

    @Override
    public String get(CallableStatement cs, String parameterName) throws SQLException {
        Object obj = cs.getObject(parameterName);
        return changeValue(obj);
    }

    private String changeValue(Object obj) throws SQLException {
        if (obj == null) {
            return null;
        }
        if (obj instanceof String) {
            return (String) obj;
        }
        Clob clob = (Clob) obj;
        return getStringValue(clob);
    }

    @Override
    public void update(ResultSet rs, String columnLabel, Object value) throws SQLException {
        StringReader reader = new StringReader((String) value);
        rs.updateCharacterStream(columnLabel, reader, ((String) value).length());
    }

    @Override
    public void update(ResultSet rs, int columnIndex, Object value) throws SQLException {
        StringReader reader = new StringReader((String) value);
        rs.updateCharacterStream(columnIndex, reader, ((String) value).length());
    }

    public Object set(PreparedStatement ps, Object obj, int i) throws SQLException {
        if (null == obj) {
            ps.setNull(i, getSqlType());
        } else {
            StringReader reader = new StringReader((String) obj);
            ps.setCharacterStream(i, reader, ((String) obj).length());
        }
        return null;
    }

    @Override
    public Object set(CallableStatement cs, Object obj, String parameterName) throws SQLException {
        if (null == obj) {
            cs.setNull(parameterName, getSqlType());
        } else {
            StringReader reader = new StringReader((String) obj);
            cs.setCharacterStream(parameterName, reader, ((String) obj).length());
        }
        return null;
    }

    @Override
    public int getSqlType() {
        return Types.CLOB;
    }

    @Override
    public Class<String> getDefaultJavaType() {
        return String.class;
    }

    public String getStringValue(Clob clob) throws SQLException {
        String value = null;
        if (clob != null) {
            Reader reader = clob.getCharacterStream();
            if (reader != null) {
                try {
                    value = IOUtils.asString(reader);
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
        }
        return value;
    }
}